package top.huntwolf.admin.service;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.huntwolf.admin.common.enums.CodeMsg;
import top.huntwolf.admin.dao.CMSUserDao;
import top.huntwolf.admin.exception.ServiceException;
import top.huntwolf.admin.pojo.cmsUser.*;
import top.huntwolf.admin.utils.RedisUtil;
import top.huntwolf.admin.utils.TokenUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service
@Transactional
public class CMSUserService {
    @Autowired
    private CMSUserDao cmsUserDao;
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RouteService routeService;

    public CMSUser findUserByName(String userName){
        return cmsUserDao.findUserByName(userName);
    }

    public String login(CMSUser user, HttpServletRequest request){
        String userName = user.getUserName();
        String userPwd = user.getUserPwd();
        String ip = request.getRemoteAddr();
        if (redisUtil.hasKey(ip)){
            int wrongTime = (int) redisUtil.get(ip);
            if (wrongTime > 5) return "FREEZE";
        }

        //登录
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userName, userPwd);
        try {
            //进入shiroRealm的认证
            subject.login(token);
        }catch (UnknownAccountException ue){
            loginFail(ip);
            throw new ServiceException(CodeMsg.USER_NOT_FOUND);
        }catch (IncorrectCredentialsException ie){
            loginFail(ip);
            throw new ServiceException(CodeMsg.WRONG_PASSWORD);
        }

        loginSuccess(ip);
        //更新登录时间
        CMSUser userDB = findUserByName(userName);
        userDB.setLastLogin(new Date());
        updateUser(userDB);

        String jwtToken = TokenUtil.getCMSToken(userName);
        return jwtToken;
    }
    //登陆失败，累加失败次数
    public void loginFail(String ip){
        if (redisUtil.hasKey(ip)) {
            redisUtil.incr(ip,1);
        }
        else {
            redisUtil.set(ip,1);
        }
    }
    //登陆成功，清空失败次数
    public void loginSuccess(String ip){
        if (redisUtil.hasKey(ip)){
            redisUtil.del(ip);
        }
    }

    public void registerSuccess(String key){
        if (redisUtil.hasKey(key)) {
            redisUtil.incr(key,1);
        }
        else {
            redisUtil.set(key,1,24*60*60);
        }
    }

    public void updateUser(CMSUser user){
        cmsUserDao.updateUser(user);
    }

    public void register(CMSUser user, HttpServletRequest request){

        String key = "register-" + request.getRemoteAddr();
        if (redisUtil.hasKey(key)){
            int wrongTime = (int) redisUtil.get(key);
            if (wrongTime > 5){
                throw new ServiceException(CodeMsg.IP_FREEZE);
            }
        }

        //验证用户名是否重复
        String userName = user.getUserName();
        if(cmsUserDao.findUserByName(userName) != null){
            throw new ServiceException(CodeMsg.USER_NAME_EXISTS);
        }

        String password = user.getUserPwd();
        //获取随机盐
        String salt = new SecureRandomNumberGenerator().nextBytes().toString();
        //进行密码加密
        String encodePwd = new SimpleHash("md5",password,salt,1024).toString();

        user.setSalt(salt);
        user.setUserPwd(encodePwd);

        cmsUserDao.insert(user);
        registerSuccess(key);

    }

    public List<CMSUser> findSubUserAndRole(){
        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());
        List<Role> roles = cmsUserDao.selectRoleByUserId(user.getId());
        int weight = 0;
        for (Role role : roles){
            if (role.getWeight()>weight){
                weight = role.getWeight();
            }
        }
        Role role = new Role();
        role.setWeight(weight);
        role.setStoreId(user.getStoreId());
        return cmsUserDao.findSubUser(role);
    }

    public List<Role> searchRoleByUserId(int id){
        return cmsUserDao.selectRoleByUserId(id);
    }

    public List<Permission> searchPermissionByRoleId(int id){
        return cmsUserDao.selectPermissionByRoleId(id);
    }

    public void addRole(Role role){
        role.setCreateTime(new Date());
        role.setUpdateTime(new Date());
        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());
        Role MyRole = cmsUserDao.selectRoleByUserIdAndWeight(user.getId());
        if (role.getWeight()>MyRole.getWeight()){
            throw new ServiceException(CodeMsg.ADD_ROLE_ERROR.fillArgs("角色权重过高"));
        }
        cmsUserDao.insertRole(role);
    }

    public void addUserAndRole(List<UserRole> userRoles){
        inspectUserRole(userRoles);
        cmsUserDao.insertUserAndRole(userRoles);
    }

    public void addPermission(Permission permission){
        permission.setCreateTime(new Date());
        permission.setUpdateTime(new Date());
        cmsUserDao.insertPermission(permission);
    }

    public void addRoleAndPermission(List<RolePermission> rolePermissions){
//        inspectRolePermission(rolePermissions);
        cmsUserDao.insertRoleAndPermission(rolePermissions);
    }

    public List<Role> findSubRoleList(){
        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());

        Role role = cmsUserDao.selectRoleByUserIdAndWeight(user.getId());

        return cmsUserDao.findSubRole(role);

    }

    public List<Permission> findPermission(){
        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());
//        List<Role> roles = cmsUserDao.selectRoleByUserId(user.getId());
//        List<Permission> permissionList = new ArrayList<>();
//        for (Role role: roles){
//            permissionList.addAll(cmsUserDao.selectPermissionByRoleId(role.getId()));
//        }
        List<Permission> permissions = cmsUserDao.findPermission(user);

        return permissions;
    }

    public void addRoleAndPermissionByRoute(RoleRoute roleRoute){

        List<RolePermission> rolePermissions = getRolePermission(roleRoute);
        cmsUserDao.insertRoleAndPermission(rolePermissions);
    }

    public List<Permission> searchPermission(CMSUser cmsUser){
        return cmsUserDao.findPermission(cmsUser);
    }

    public void deleteRoleAndPermissionByRoute(RoleRoute roleRoute){
        List<RolePermission> rolePermissions = getRolePermission(roleRoute);
        cmsUserDao.deleteRoleAndPermission(rolePermissions);
    }

    public void deleteUserAndRole(List<UserRole> userRoles){
        inspectUserRole(userRoles);
        cmsUserDao.deleteUserAndRole(userRoles);
    }

    public void deleteRoleAndPermission(List<RolePermission> rolePermissions){
        inspectRolePermission(rolePermissions);
        cmsUserDao.deleteRoleAndPermission(rolePermissions);
    }

    //根据路由获取登录用户的权限
    private List<RolePermission> getRolePermission(RoleRoute roleRoute) {

        //判断是否有此路由
        List<Route> routes = routeService.searchAllRoute();
        boolean flag = false;
        for (Route route : routes){
            if (route.getId().equals(roleRoute.getRoleId())) {
                flag = true;
                break;
            }
        }
        if (!flag&&cmsUserDao.selectPermissionByRoute(roleRoute.getRouteId()).get(0)==null){
            throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("没有此路由信息"));
        }

        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());
        Role MyRole = cmsUserDao.selectRoleByUserIdAndWeight(user.getId());
        Role role = cmsUserDao.selectRole(roleRoute.getRoleId());
        if (role == null){
            throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("角色不存在"));
        }
        if (role.getWeight()>=MyRole.getWeight()){
            throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("角色权重过高"));
        }

        List<Permission> permissionList = cmsUserDao.findPermission(user);
        List<Permission> permissions = permissionList.stream().filter(permission -> permission.getRouteId().equals(roleRoute.getRouteId())).collect(Collectors.toList());
        if(permissions.size()==0){
            throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("不拥有该路由的权限"));
        }
        List<RolePermission> rolePermissions = new ArrayList<>();
        for (Permission permission : permissions){
            RolePermission rolePermission = new RolePermission(roleRoute.getRoleId(),permission.getId());
            rolePermissions.add(rolePermission);
        }
        return rolePermissions;
    }



    public void inspectRolePermission(List<RolePermission> rolePermissions) {
        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());
        Role MyRole = cmsUserDao.selectRoleByUserIdAndWeight(user.getId());
        List<Permission> permissionList = cmsUserDao.findPermission(user);

        for (RolePermission rolePermission : rolePermissions){
            Role role = cmsUserDao.selectRole(rolePermission.getRoleId());
            if (role == null){
                throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("角色不存在"));
            }
            if (role.getWeight()>MyRole.getWeight()){
                throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("角色权重过高"));
            }
            boolean flag = false;
            for (Permission permission : permissionList){
                if (permission.getId().equals(rolePermission.getPermissionId())){
                    flag = true;
                    break;
                }
            }
            if (!flag){
                throw new ServiceException(CodeMsg.ADD_ROLE_PERMISSION_ERROR.fillArgs("权限等级过高"));
            }
        }
    }


    public void inspectUserRole(List<UserRole> userRoles) {

        CMSUser user = cmsUserDao.findUserByName(TokenUtil.getUserName());
        Role MyRole = cmsUserDao.selectRoleByUserIdAndWeight(user.getId());

        for (UserRole userRole : userRoles){
            if (cmsUserDao.selectUserById(userRole.getUserId())==null){
                throw new ServiceException(CodeMsg.USER_NOT_EXIST);
            }
            Role role = cmsUserDao.selectRole(userRole.getRoleId());
            if (role == null){
                throw new ServiceException(CodeMsg.ADD_USER_ROLE_ERROR.fillArgs("角色不存在"));
            }
            if (role.getWeight()>MyRole.getWeight()){
                throw new ServiceException(CodeMsg.ADD_USER_ROLE_ERROR.fillArgs("角色权重过高"));
            }
        }
    }


}
